﻿using System.Collections.Generic;
using System.Runtime.Serialization;

namespace ModelLayer
{
    [DataContract]
    public class Node : IHasNeighbours<Node>
    {
        private bool _visited;
        private double _totalCost;
        private Edge _cameFromEdge;

        public Node(Station s)
        {
            Station = s;
            Edges = new List<Edge>();
            _visited = false;
            _totalCost = -1;
            ChargeHere = false;
        }

        [DataMember]
        public Station Station { get; set; }

        [DataMember]
        public double TotalCost
        {
            get { return _totalCost; }
            set { _totalCost = value; }
        }

        [DataMember]
        public List<Edge> Edges { get; set; }

        [DataMember]
        public Edge EdgeCameFrom
        {
            get { return _cameFromEdge; }
            set { _cameFromEdge = value; }
        }

        /// <summary>
        /// Gets or sets a value indicating whether this <see cref="Node"/> is visited.
        /// </summary>
        /// <value><c>true</c> if visited; otherwise, /c>.</value>
        [DataMember]
        public bool Visited
        {
            get { return _visited; }
            set { _visited = value; }
        }

        /// <summary>
        /// Gets or sets a value indicating whether [charge here].
        /// </summary>
        /// <value><c>true</c> if [charge here]; otherwise, /c>.</value>
        [DataMember]
        public bool ChargeHere { get; set; }

        public int CompareTo(Node n)
        {
            return _totalCost.CompareTo(n.TotalCost);
        }

        /// <summary>
        /// Determines whether the specified <see cref="System.Object" /> is equal to this instance.
        /// </summary>
        /// <param name="obj">The object to compare with the current object.</param>
        /// <returns><c>true</c> if the specified <see cref="System.Object" /> is equal to this
        /// instance; otherwise, /c>.</returns>
        public override bool Equals(object obj)
        {
            Node n = obj as Node;
            return Station.Id.Equals(n.Station.Id);
        }

        /// <summary>
        /// Returns a hash code for this instance.
        /// </summary>
        /// <returns>A hash code for this instance, suitable for use in hashing algorithms and data
        /// structures like a hash table.</returns>
        public override int GetHashCode()
        {
            return Station.Id.GetHashCode();
        }

        /// <summary>
        /// Resets values on this node instance.
        /// </summary>
        public void Reset()
        {
            _visited = false;
            _cameFromEdge = null;
            _totalCost = -1;
        }

        public override string ToString()
        {
            return Station.ToString();
        }

        public IEnumerable<Node> Neighbours
        {
            get
            {
                return GetNeighbours(this);
            }
        }

        /// <summary>
        /// Gets the neighbour nodes from this node instance.
        /// </summary>
        /// <param name="node">The node.</param>
        /// <returns>List{Node}.</returns>
        private IEnumerable<Node> GetNeighbours(Node node)
        {
            List<Node> retList = new List<Node>();
            foreach (Edge edge in Edges)
            {
                retList.Add(node.Station.Id == edge.FirstNode.Station.Id ? edge.SecondNode : edge.FirstNode);
            }

            return retList;
        }

        /// <summary>
        /// Sets the neigbour nodes for this node instance.
        /// </summary>
        /// <param name="edges">The edges.</param>
        public void SetNeigbors(List<Edge> edges)
        {
            Edges = edges;
        }
    }
}